﻿
using System;
namespace ANLP
{
    public enum ParserStatus
    {
        EOF = 1,
        Succeed = 0,
        Failed = -1,
        SyntaxError = -2,
    }

    public struct ParserExpression<TExpression>
    {
        public ParserExpression(string text)
            : this()
        {
            this.Text = text;
        }

        public TExpression Value { get; set; }
        public string Text { get; set; }

        public static implicit operator TExpression(ParserExpression<TExpression> item)
        {
            return item.Value;
        }

        public static implicit operator string(ParserExpression<TExpression> item)
        {
            return item.Text;
        }
    }

    public abstract class Parser<TExpression>
    {
        protected LexerBase lexer;

        public Parser(LexerBase lexer)
        {
            this.lexer = lexer;
        }

        protected abstract int[][] States { get; }
        protected abstract int[][] Rules { get; }

        int currentStateNumber, currentRuleNumber;
        int[] currentState;

        private ParserStatus TryState(int stateNumber, out ParserExpression<TExpression> result)
        {
            int currentStateNumber = this.currentStateNumber;
            this.currentStateNumber = stateNumber;
            int[] currentState = States[stateNumber];
            ParserExpression<TExpression>[] items = new ParserExpression<TExpression>[currentState.Length + 1];
            items[currentState.Length] = new ParserExpression<TExpression>(null);
            items[currentState.Length].Value = lastRecursiveResult.Value;
            DoAction(stateNumber, -1, items);
            ParserStatus state = TryState(States[stateNumber], out result, currentStateNumber == stateNumber, items);
            this.currentStateNumber = currentStateNumber;
            return state;
        }

        private ParserStatus TryState(int[] state, out ParserExpression<TExpression> result, bool recursive, ParserExpression<TExpression>[] items)
        {
            int token = 0;
            for (int step = 0; step < state.Length; step++)
            {

                int action = state[step];

                //Terminal
                if (action > 0)
                {
                    token = lexer.Next(action);

                    //Whitespace
                    if (token == 0)
                    {
                        step--;
                        continue;
                    }

                    if (step > 0 && token == -2)
                    {
                        result = default(ParserExpression<TExpression>);
                        return ParserStatus.SyntaxError;
                    }

                    //EOF
                    if (token == -1)
                    {
                        result = default(ParserExpression<TExpression>);
                        return ParserStatus.EOF;
                    }
                    items[step] = new ParserExpression<TExpression>(lexer.GetText());

                    if (action == token)
                    {
                        items[state.Length].Text += items[step].Text;
                        DoAction(currentStateNumber, step, items);
                    }
                    else
                    {
                        result = default(ParserExpression<TExpression>);
                        if (step == 0)
                            return ParserStatus.Failed;
                        return ParserStatus.SyntaxError;
                    }
                }
                else
                //Non-Terminal
                {
                    switch (TryRule(-action, out result, recursive))
                    {
                        case ParserStatus.Failed:
                        case ParserStatus.SyntaxError:
                            return ParserStatus.Failed;
                        case ParserStatus.Succeed:
                            items[step] = result;
                            DoAction(currentStateNumber, step, items);
                            break;
                        case ParserStatus.EOF:
                            return ParserStatus.EOF;
                    }
                }
            }
            DoAction(this.currentStateNumber, int.MaxValue, items);
            result = items[items.Length - 1];
            return ParserStatus.Succeed;

        }

        private ParserStatus TryRule(int ruleNumber, out ParserExpression<TExpression> result, bool recursive)
        {
            int currentRuleNumber = this.currentRuleNumber;
            int currentStateNumber = this.currentStateNumber;
            this.currentRuleNumber = ruleNumber;
            ParserStatus state = TryRule(Rules[ruleNumber], out result, recursive || currentRuleNumber == ruleNumber);
            this.currentRuleNumber = currentRuleNumber;
            this.currentStateNumber = currentStateNumber;
            return state;
        }

        private ParserStatus TryRule(int[] rule, out ParserExpression<TExpression> result, bool recursive)
        {
            int currentLexerPosition = lexer.Position;
            int action;
            for (int ruleStep = 0; ruleStep < rule.Length; ruleStep++)
            {
                action = rule[ruleStep];
                if (!recursive)
                {
                    if (recursive = currentRuleNumber == action)
                        continue;
                }
                else
                {
                    if (currentRuleNumber == action || currentStateNumber == -action)
                    {
                        //TODO Treat the recursive rule
                    }
                }
                if (currentRuleNumber == action || currentStateNumber == -action)
                    continue;

                if (action >= 0)
                {
                    switch (TryRule(action, out result, false))
                    {
                        case ParserStatus.SyntaxError:
                            result = default(ParserExpression<TExpression>);
                            return ParserStatus.SyntaxError;
                        case ParserStatus.EOF:
                            if (ruleStep <= rule.Length - 1)
                            {
                                lexer.Position = currentLexerPosition;
                                currentRule = rule;
                                this.currentRuleNumber = action;
                                continue;
                            }
                            else
                                if (recursive)
                                {
                                    result = lastRecursiveResult;
                                    return ParserStatus.Succeed;
                                }
                                else
                                {
                                    result = default(ParserExpression<TExpression>);
                                    return ParserStatus.EOF;
                                }
                        case ParserStatus.Succeed:
                            ParserStatus resultStatus = ParserStatus.Succeed;
                            currentLexerPosition = lexer.Position;
                            if (recursive)
                                resultStatus = TryRule(rule, out result, recursive);
                            if (resultStatus == ParserStatus.Failed)
                            {
                                lexer.Position = currentLexerPosition;
                                return ParserStatus.Succeed;
                            }
                            return resultStatus;
                        case ParserStatus.Failed:
                            {
                                lexer.Position = currentLexerPosition;
                                currentRule = rule;
                                this.currentRuleNumber = action;
                                continue;
                            }
                    }
                }
                else
                {
                    switch (TryState(-action, out result))
                    {
                        case ParserStatus.EOF:
                            if (ruleStep < rule.Length - 1)
                                lexer.Position = currentLexerPosition;
                            else
                                if (recursive && lastRecursiveResult.Value != null)
                                {
                                    result = lastRecursiveResult;
                                    return ParserStatus.Succeed;
                                }
                                else
                                    return ParserStatus.EOF;
                            break;
                        case ParserStatus.Succeed:
                            {

                                ParserExpression<TExpression> lastResult = result;
                                ParserStatus resultStatus = ParserStatus.Succeed;
                                currentLexerPosition = lexer.Position;
                                if (recursive)
                                {
                                    lastRecursiveResult = result;
                                    resultStatus = TryRule(rule, out result, recursive);
                                }
                                lastRecursiveResult = default(ParserExpression<TExpression>);
                                if (resultStatus == ParserStatus.Failed)
                                {
                                    result = lastResult;
                                    lexer.Position = currentLexerPosition;
                                    return ParserStatus.Succeed;
                                }

                                return resultStatus;
                            }
                        case ParserStatus.SyntaxError:
                        case ParserStatus.Failed:
                            lexer.Position = currentLexerPosition;
                            break;
                    }
                }
            }
            result = default(ParserExpression<TExpression>);
            return ParserStatus.Failed;
        }

        ParserExpression<TExpression> lastRecursiveResult;

        [Obsolete]
        private ParserStatus ParseLoop(out ParserExpression<TExpression> result)
        {
            int token = 0;
            result = new ParserExpression<TExpression>(null);
            ParserExpression<TExpression>[] items = new ParserExpression<TExpression>[currentState.Length + 1];
            for (int step = 0; step < currentState.Length; step++)
            {

                int action = currentState[step];

                //Terminal
                if (action > 0)
                {
                    token = lexer.Next(action);

                    //Whitespace
                    if (token == 0)
                    {
                        step--;
                        continue;
                    }

                    if (step == 0 && token == -2)
                        return ParserStatus.SyntaxError;

                    //EOF
                    if (token == -1)
                        return ParserStatus.EOF;

                    items[step] = new ParserExpression<TExpression>(lexer.GetText());

                    if (action == token)
                        DoAction(currentStateNumber, step, items);
                    else
                        return ParserStatus.Failed;
                    //else
                    //step++;
                }
                else
                //Non-Terminal
                {
                    int[] rule = currentRule;
                    currentRule = Rules[-action];
                    currentRuleNumber = -action;
                    int currentStateNumber = this.currentStateNumber;
                    switch (TryParse(-action, out result))
                    {
                        case ParserStatus.Failed:
                        case ParserStatus.SyntaxError:
                            return ParserStatus.Failed;
                        case ParserStatus.Succeed:
                            DoAction(currentStateNumber, step, items);
                            break;
                    }

                    currentRule = rule;
                    currentState = States[currentStateNumber];
                    this.currentStateNumber = currentStateNumber;
                }
            }
            DoAction(this.currentStateNumber, int.MaxValue, items);
            result = items[items.Length - 1];
            return ParserStatus.Succeed;
        }

        [Obsolete]
        private ParserStatus TryParse(int currentRuleNumber, out ParserExpression<TExpression> result)
        {
            result = default(ParserExpression<TExpression>);
            bool recursive = false;
            int currentLexerPosition = lexer.Position;
            int action;
            for (int ruleStep = 0; ruleStep < currentRule.Length; ruleStep++)
            {
                action = currentRule[ruleStep];
                if (currentRule == null)
                    currentStateNumber = 0;
                else
                {
                    //IsRecursiveRule
                    if (!recursive)
                    {
                        if (recursive = currentRuleNumber == action)
                            continue;
                    }
                    if (currentRuleNumber == action)
                        continue;


                    if (action >= 0)
                    {
                        this.currentRuleNumber = action;
                        int[] rule = currentRule;
                        currentRule = Rules[action];
                        switch (TryParse(action, out result))
                        {
                            case ParserStatus.SyntaxError:
                            case ParserStatus.Failed:
                                {
                                    lexer.Position = currentLexerPosition;
                                    currentRule = rule;
                                    this.currentRuleNumber = action;
                                    continue;
                                }
                            case ParserStatus.EOF:
                                return ParserStatus.EOF;
                        }
                    }
                    else
                        currentStateNumber = -action;
                }
                if (action < 0)
                {
                    currentState = States[currentStateNumber];

                    DoAction(currentStateNumber, -1, null);
                    switch (ParseLoop(out result))
                    {
                        //case ParserStatus.SyntaxError:
                        //    return ParserStatus.SyntaxError;
                        case ParserStatus.Succeed:
                            if (!recursive)
                                return ParserStatus.Succeed;
                            else
                            {
                                //currentRule = rule;
                                currentRule = Rules[currentRuleNumber];
                                TryParse(currentRuleNumber, out result);
                                return ParserStatus.Succeed;
                            }
                        case ParserStatus.EOF:
                            return ParserStatus.EOF;
                        default:
                            lexer.Position = currentLexerPosition;
                            break;
                    }
                    this.currentRule = Rules[currentRuleNumber];
                    this.currentRuleNumber = currentRuleNumber;
                }
                else
                {
                    if (!recursive)
                    {
                        result = default(ParserExpression<TExpression>);
                        return 0;
                    }
                    else
                    {
                        //currentRule = rule;
                        currentRule = Rules[currentRuleNumber];
                        this.currentRuleNumber = currentRuleNumber;
                        if (TryParse(currentRuleNumber, out result) == ParserStatus.EOF)
                            return ParserStatus.EOF;
                        return ParserStatus.Succeed;
                    }
                }
            }
            return ParserStatus.Failed;
        }

        protected ParserExpression<TExpression> program;
        private int[] currentRule;

        protected abstract void DoAction(int state, int step, ParserExpression<TExpression>[] expressions);

        protected delegate ParserStatus ParseAction<T>(ParserExpression<TExpression>[] expressions, out T result) where T : TExpression;

        public TExpression Parse(string program)
        {
            lexer.Read(program);
            currentRuleNumber = -1;
            //DoAction(0, 0);
            if (TryState(0, out this.program) == ParserStatus.Failed)
                throw new InvalidSyntaxException("Syntax Error at line " + lexer.Line + ", char " + lexer.CharPosition);

            DoAction(-1, 0, null);

            return this.program.Value;
        }
    }
}
